package com.fezs.security.service;

import com.fezs.common.constants.CacheConstant;
import com.fezs.redis.utils.RedisUtils;
import com.fezs.security.utils.SecurityUtils;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.SneakyThrows;

import java.time.Duration;

/**
 * 默认的 {@link SecurityPermissionService} 实现类
 */
public class SecurityPermissionServiceImpl implements SecurityPermissionService {

    /**
     * 针对 {@link #hasAnyPermissions(String...)} 的缓存
     */
    private final Cache<String, Boolean> hasAnyPermissionsCache = CacheBuilder.newBuilder()
        .expireAfterWrite(Duration.ofMinutes(1))
        .build();

    /**
     * 针对 {@link #hasAnyRoles(String...)} 的缓存
     */
    private final Cache<String, Boolean> hasAnyRolesCache = CacheBuilder.newBuilder()
        .expireAfterWrite(Duration.ofMinutes(1))
        .build();

    @Override
    public boolean hasPermission(String permission) {
        return hasAnyPermissions(permission);
    }

    @Override
    @SneakyThrows
    public boolean hasAnyPermissions(String... permissions) {
        String key = CacheConstant.contact(CacheConstant.USER_PERMISSION, SecurityUtils.getUserId());
        for (String perm : permissions) {
            String localCacheKey = key + ":" + perm;
            boolean flag = hasAnyPermissionsCache.get(localCacheKey, () -> RedisUtils.getCacheSetContains(key, perm));
            if (flag) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean hasRole(String role) {
        return hasAnyRoles(role);
    }

    @Override
    @SneakyThrows
    public boolean hasAnyRoles(String... roles) {
        String key = CacheConstant.contact(CacheConstant.USER_ROLE, SecurityUtils.getUserId());
        for (String role : roles) {
            String localCacheKey = key + ":" + role;
            boolean flag = hasAnyRolesCache.get(localCacheKey, () -> RedisUtils.getCacheSetContains(key, role));
            if (flag) {
                return true;
            }
        }
        return false;
    }

}
